package com.afkt.project.ui.widget.render.scenery;

import com.afkt.project.util.LogUtils;
import com.ohos.afkt.ResourceTable;
import com.dev.utils.app.ResourceUtils;
import com.dev.utils.app.SizeUtils;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Point;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class LoadingViewDiv extends Component {

    public static final int MODE_NORMAL     = 0;
    public static final int MODE_LEAF_COUNT = 1;

    private static final String PERCENTAGE_100 = "100%";

    private static final long ANIMATION_DURATION = 7333;

    private static final int LEAF_COUNT          = 28;
    private static final int DEGREE_180          = 180;
    private static final int DEGREE_360          = 360;
    private static final int FULL_GROUP_ROTATION = (int) (5.25f * DEGREE_360);

    private static final int DEFAULT_PROGRESS_COLOR             = 0xfffca72e;
    private static final int DEFAULT_PROGRESS_BGCOLOR           = 0xfffcd49f;
    private static final int DEFAULT_ELECTRIC_FAN_BGCOLOR       = 0xfffccc59;
    private static final int DEFAULT_ELECTRIC_FAN_OUTLINE_COLOR = Color.WHITE.getValue();

    private static final float DEFAULT_WIDTH                  = 182.0f;
    private static final float DEFAULT_HEIGHT                 = 65.0f;
    private static final float DEFAULT_TEXT_SIZE              = 11.0f;
    private static final float DEFAULT_STROKE_WIDTH           = 2.0f;
    private static final float DEFAULT_STROKE_INTERVAL        = .2f;
    private static final float DEFAULT_CENTER_RADIUS          = 16.0f;
    private static final float DEFAULT_PROGRESS_CENTER_RADIUS = 11.0f;

    private static final float DEFAULT_LEAF_FLY_DURATION_FACTOR = 0.1f;

    private static final float LEAF_CREATE_DURATION_INTERVAL  = 1.0f / LEAF_COUNT;
    private static final float DECELERATE_DURATION_PERCENTAGE = 0.4f;
    private static final float ACCELERATE_DURATION_PERCENTAGE = 0.6f;

    private final Paint mPaint                 = new Paint();
    private final RectFloat mTempBounds            = new RectFloat();
    private final RectFloat mCurrentProgressBounds = new RectFloat();


    private float mTextSize;
    private float mStrokeXInset;
    private float mStrokeYInset;
    private float mProgressCenterRadius;

    private float mScale = 1.0f;
    private float mRotation;
    private float mProgress;

    private float mNextLeafCreateThreshold;

    private int mProgressColor;
    private int mProgressBgColor;
    private int mElectricFanBgColor;
    private int mElectricFanOutlineColor;

    private float mStrokeWidth;
    private float mCenterRadius;

    private PixelMapElement mLeafDrawable;
    private PixelMapElement mLoadingDrawable;
    private PixelMap mElectricFanDrawable;

    private int mMode;
    private int mCurrentLeafCount;
    public LoadingViewDiv(Context context) {
        super(context);
        init();
    }

    public LoadingViewDiv(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init();
    }

    public LoadingViewDiv(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
    }

    public LoadingViewDiv(Context context, AttrSet attrSet, int resId) {
        super(context, attrSet, resId);
        init();
    }


    private static final String TAG = LoadingViewDiv.class.getSimpleName();
    AnimatorValue animatorValue = new AnimatorValue();
    private void init() {
        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#3F51B5")));
        setBackground(shapeElement);
        mDuration = ANIMATION_DURATION;
        mWidth = SizeUtils.dipConvertPx(DEFAULT_WIDTH);
        mHeight = SizeUtils.dipConvertPx(DEFAULT_HEIGHT);
        mTextSize = SizeUtils.dipConvertPx(DEFAULT_TEXT_SIZE);
        mStrokeWidth = SizeUtils.dipConvertPx(DEFAULT_STROKE_WIDTH);
        mCenterRadius = SizeUtils.dipConvertPx(DEFAULT_CENTER_RADIUS);
        mProgressCenterRadius = SizeUtils.dipConvertPx(DEFAULT_PROGRESS_CENTER_RADIUS);

        mProgressColor = DEFAULT_PROGRESS_COLOR;
        mProgressBgColor = DEFAULT_PROGRESS_BGCOLOR;
        mElectricFanBgColor = DEFAULT_ELECTRIC_FAN_BGCOLOR;
        mElectricFanOutlineColor = DEFAULT_ELECTRIC_FAN_OUTLINE_COLOR;
        try {
            mLeafDrawable = new PixelMapElement(getContext().getResourceManager().getResource(ResourceTable.Media_icon_electric_leaf));
            mLoadingDrawable = new PixelMapElement(getContext().getResourceManager().getResource(ResourceTable.Media_icon_electric_loading));
        } catch (Exception e) {

        }
        addDrawTask(task);
        animatorValue.setValueUpdateListener(new ProgressAnimatorValue());
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setDuration(mDuration);


        setLayoutRefreshedListener(new LayoutRefreshedListener() {
            @Override
            public void onRefreshed(Component component) {
                LogUtils.error(TAG, "onRefreshed");
               // animatorValue.cancel();
                AnimatorGroup animatorGroup = new AnimatorGroup();
                List<AnimatorValue> lists = new ArrayList<>();
                for (int i = 0; i <mLeafHolders.size(); i++) {
                    animatorGroup.runParallel(mLeafHolders.get(i).animatorValue);
                }
                animatorGroup.runParallel(animatorValue);
                animatorGroup.cancel();
                animatorGroup.start();
               // animatorValue.start();
             /*   for (int i = 0; i < mLeafHolders.size(); i ++) {
                    mLeafHolders.get(i).animatorValue.cancel();
                }*/


            }
        });
    }


    private AnimatorValue mRenderAnimator;

    protected long mDuration;

    protected float mWidth;
    protected float mHeight;
    private DrawTask task = new DrawTask() {
        @Override
        public void onDraw(Component component, Canvas canvas) {
            int saveCount = canvas.save();

            RectFloat arcBounds = mTempBounds;
            copy(arcBounds, new Rect(getLeft() + getWidth()/4 , getTop() + getHeight()/2,
                    getRight() - getWidth() / 4 , getBottom() -getHeight() / 2 + 50));
            arcBounds.setPivot(mStrokeXInset, mStrokeYInset);

            mCurrentProgressBounds.left = arcBounds.left + 20;
            mCurrentProgressBounds.right = arcBounds.right;
            mCurrentProgressBounds.bottom = arcBounds.bottom + 100;
            mCurrentProgressBounds.top = arcBounds.bottom - 2 * mCenterRadius;
            //draw progress background
            float progressInset = mCenterRadius - mProgressCenterRadius;
            RectFloat progressRect  = new RectFloat(mCurrentProgressBounds);

            //sub DEFAULT_STROKE_INTERVAL, otherwise will have a interval between progress background and progress outline
            progressRect.setPivot(progressInset - DEFAULT_STROKE_INTERVAL, progressInset - DEFAULT_STROKE_INTERVAL);
            mPaint.setColor(new Color(mProgressBgColor));
            mPaint.setStyle(Paint.Style.FILL_STYLE);
            canvas.drawRoundRect(progressRect, mProgressCenterRadius, mProgressCenterRadius, mPaint);


            // 绘制椭圆
            RectFloat progressOutlineRect    = new RectFloat(mCurrentProgressBounds);
            float progressOutlineStrokeInset = (mCenterRadius - mProgressCenterRadius) / 2.0f;
            progressOutlineRect.setPivot(progressOutlineStrokeInset, progressOutlineStrokeInset);
            mPaint.setStyle(Paint.Style.STROKE_STYLE);
            mPaint.setColor(new Color(mProgressBgColor));
            mPaint.setStrokeWidth(mCenterRadius - mProgressCenterRadius);
            LogUtils.error(TAG, "progressOutlineRect = " + progressOutlineRect);
            //mCenterRadius = 45;
           // mProgressCenterRadius = 90;
            canvas.drawRoundRect(progressOutlineRect, mCenterRadius, mCenterRadius, mPaint);
            progressRect.left = progressRect.left + 20;
            progressRect.right = progressRect.right - 20;
            progressRect.top = progressRect.top + 20;
            progressRect.bottom = progressRect.bottom - 20;
            //draw progress
            mPaint.setColor(new Color(mProgressColor));
            mPaint.setStyle(Paint.Style.FILL_STYLE);
            canvas.drawPath(createProgressPath(mProgress, mProgressCenterRadius, progressRect), mPaint);

            //draw leaves
            for (int i = 0; i < mLeafHolders.size(); i++) {
             LogUtils.error(TAG, "i = " + i);
                int        leafSaveCount = canvas.save();
                LeafHolder leafHolder    = mLeafHolders.get(i);
                Rect      leafBounds    = leafHolder.mLeafRect;
                canvas.rotate(leafHolder.mLeafRotation, leafBounds.getCenterX(), leafBounds.getCenterY());
                mLeafDrawable.setBounds(leafBounds);
                RectFloat rectFloat = new RectFloat();
                rectFloat.left = (float) leafBounds.left;
                rectFloat.right = (float) leafBounds.right + 42;
                rectFloat.top = (float) leafBounds.top;
                rectFloat.bottom = (float) leafBounds.bottom + 30;
                mPaint.setStyle(Paint.Style.STROKE_STYLE);
                LogUtils.error(TAG, " BezierListener mLeafRect = " + rectFloat.left + " " + rectFloat.right);
                Paint newPaint = new Paint();
                PixelMap pixelMap = ResourceUtils.getPixelMapFromResource(ResourceTable.Media_icon_electric_leaf);
                LogUtils.error(TAG, "pixelMap = " + pixelMap);
                if (leafBounds.left == 0 || leafBounds.top == 0) continue;
                LogUtils.error(TAG, "refctFloat left =  " + rectFloat.left + " top = " + rectFloat.top
                    + " right = " + rectFloat.right + " bottom = " + rectFloat.bottom);
                canvas.drawPixelMapHolderRect(new PixelMapHolder(pixelMap), rectFloat,  newPaint);
                canvas.restoreToCount(leafSaveCount);
            }
//draw electric fan outline
            float electricFanCenterX = arcBounds.right - mCenterRadius;
            float electricFanCenterY = arcBounds.bottom - mCenterRadius;;
            mStrokeWidth = 10;
            mPaint.setColor(new Color(mElectricFanOutlineColor));
            mPaint.setStyle(Paint.Style.STROKE_STYLE);
            mPaint.setStrokeWidth(mStrokeWidth);

            canvas.drawCircle(electricFanCenterX + 30, electricFanCenterY + 56,
                    120 / 2 * mScale , mPaint);

            //draw electric background
            mPaint.setColor(new Color(mElectricFanBgColor));
            mPaint.setStyle(Paint.Style.FILL_STYLE);
       /*     canvas.drawCircle(arcBounds.right - mCenterRadius, arcBounds.bottom - mCenterRadius,
                    mCenterRadius - mStrokeWidth + DEFAULT_STROKE_INTERVAL, mPaint);
*/
            canvas.drawCircle(electricFanCenterX + 30, electricFanCenterY + 56,
                    100 / 2 * mScale, mPaint);


            //draw electric fan
            int rotateSaveCount = canvas.save();
            canvas.rotate(mRotation, electricFanCenterX + 30, electricFanCenterY + 56 );
            RectFloat rectFloat = new RectFloat((electricFanCenterX + 30 - 90 / 2 * mScale),
                   (electricFanCenterY + 56 - 90 / 2 * mScale),
                  (electricFanCenterX + 30 + 90 / 2 * mScale),
                 (electricFanCenterY + 56 + 90 / 2 * mScale));

            LogUtils.error(TAG, "electric refctFloat left =  " + rectFloat.left + " top = " + rectFloat.top
                    + " right = " + rectFloat.right + " bottom = " + rectFloat.bottom);

            canvas.drawPixelMapHolderRect(new PixelMapHolder(ResourceUtils.getPixelMapFromResource(ResourceTable.Media_icon_electric_fan)), rectFloat, mPaint);


            //draw 100% text
            if (mScale <= 1.0f) {
                mPaint.setTextSize((int)( mTextSize));
                mPaint.setColor(new Color(mElectricFanOutlineColor));
                Rect textRect = new Rect();
                mPaint.getTextBounds(PERCENTAGE_100);
                float textWidth =  electricFanCenterX - textRect.getWidth() / 2.0f;
                float textHeight =  electricFanCenterY + textRect.getHeight() / 2.0f;

                canvas.drawText(mPaint, PERCENTAGE_100, textWidth,
                        textHeight);
            }


            canvas.restoreToCount(rotateSaveCount);
        }
    };



    private  class  ProgressAnimatorValue implements AnimatorValue.ValueUpdateListener {

        public ProgressAnimatorValue() {

        }
        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {
         //   LogUtils.error(TAG, "v = " + v);
            if (v < DECELERATE_DURATION_PERCENTAGE) {
                mProgress = v / DECELERATE_DURATION_PERCENTAGE * DECELERATE_DURATION_PERCENTAGE;
            } else {
                mProgress =(v - DECELERATE_DURATION_PERCENTAGE) / ACCELERATE_DURATION_PERCENTAGE * ACCELERATE_DURATION_PERCENTAGE + DECELERATE_DURATION_PERCENTAGE;
            }

            addDrawTask(task);
        }
    }
    private Path createProgressPath(
            float progress,
            float circleRadius,
            RectFloat progressRect
    ) {
        RectFloat arcProgressRect  = new RectFloat(progressRect.left, progressRect.top, progressRect.left + circleRadius * 2, progressRect.bottom);
        RectFloat rectProgressRect = null;

        float progressWidth = progress * progressRect.getWidth();
        float progressModeWidth = mMode == MODE_LEAF_COUNT ?
                (float) mCurrentLeafCount / (float) LEAF_COUNT * progressRect.getWidth() : progress * progressRect.getWidth();

        float swipeAngle = DEGREE_180;
        //the left half circle of the progressbar
        if (progressModeWidth < circleRadius) {
            swipeAngle = progressModeWidth / circleRadius * DEGREE_180;
        }

        //the center rect of the progressbar
        if (progressModeWidth < progressRect.getWidth() - circleRadius && progressModeWidth >= circleRadius) {
            rectProgressRect = new RectFloat(progressRect.left + circleRadius, progressRect.top, progressRect.left + progressModeWidth, progressRect.bottom);
        }

        //the right half circle of the progressbar
        if (progressWidth >= progressRect.getWidth() - circleRadius) {
            rectProgressRect = new RectFloat(progressRect.left + circleRadius, progressRect.top, progressRect.right - circleRadius, progressRect.bottom);
            mScale = (progressRect.getWidth() - progressWidth) / circleRadius;
        }

        //the left of the right half circle
        if (progressWidth < progressRect.getWidth() - circleRadius) {
            mRotation = (progressWidth / (progressRect.getWidth() - circleRadius)) * FULL_GROUP_ROTATION % DEGREE_360;

            RectFloat leafRect = new RectFloat(progressRect.left + progressWidth, progressRect.top, progressRect.right - circleRadius, progressRect.bottom);
            addLeaf(progress, leafRect);
        }

        Path path = new Path();
        path.addArc(arcProgressRect, DEGREE_180 - swipeAngle / 2, swipeAngle);

        if (rectProgressRect != null) {
            path.addRect(rectProgressRect, Path.Direction.CLOCK_WISE);
        }

        return path;
    }
    private static final List<LeafHolder> mLeafHolders      = new ArrayList<>();
    private void addLeaf(
            float progress,
            RectFloat leafFlyRect
    ) {

        LogUtils.error(TAG, "addLeaf");

        if (progress < mNextLeafCreateThreshold) {
            return;
        }
        mNextLeafCreateThreshold += LEAF_CREATE_DURATION_INTERVAL;

       LeafHolder leafHolder = new LeafHolder();
        mLeafHolders.add(leafHolder);

        AnimatorValue leafAnimator = getAnimator(leafHolder, leafFlyRect, progress);
        leafHolder.animatorValue = leafAnimator;
        leafAnimator.setStateChangedListener(new DivStateChange(leafHolder));
        leafAnimator.start();
    }
    public  class LeafHolder {
        public Rect mLeafRect     = new Rect();
        public float mLeafRotation = 0.0f;

        public float mMaxRotation = mRandom.nextInt(120);

        public AnimatorValue animatorValue;
    }
    private static final Random mRandom           = new Random();

    private AnimatorValue getAnimator(
            LeafHolder target,
            RectFloat leafFlyRect,
            float progress
    ) {
        AnimatorValue bezierValueAnimator = getBezierValueAnimator(target, leafFlyRect, progress);
        // 暂时只有线性滑动
        bezierValueAnimator.setCurveType(Animator.CurveType.LINEAR);
        return bezierValueAnimator;
    }

    private AnimatorValue getBezierValueAnimator(
            LeafHolder target,
            RectFloat leafFlyRect,
            float progress
    ) {
        // BezierEvaluator evaluator = new BezierEvaluator(getPoint1(leafFlyRect), getPoint2(leafFlyRect));

        AnimatorValue animator = new AnimatorValue();

        animator.setValueUpdateListener(new BezierListener(target, leafFlyRect));
        //animator.setTarget(target);
        animator.setDuration((long) ((mRandom.nextInt(300) + mDuration * DEFAULT_LEAF_FLY_DURATION_FACTOR) * (1.0f - progress)));

        return animator;
    }

    private void copy(RectFloat src, Rect des) {
        src.left = des.left;
        src.right = des.right;
        src.bottom = des.bottom;
        src.top = des.top;
    }

    private class DivStateChange implements Animator.StateChangedListener {

        private LeafHolder target;
        public DivStateChange(LeafHolder leafHolder) {
            target = leafHolder;
        }
        @Override
        public void onStart(Animator animator) {

        }

        @Override
        public void onStop(Animator animator) {

        }

        @Override
        public void onCancel(Animator animator) {

        }

        @Override
        public void onEnd(Animator animator) {
            mLeafHolders.remove(target);
            mCurrentLeafCount++;
        }

        @Override
        public void onPause(Animator animator) {

        }

        @Override
        public void onResume(Animator animator) {

        }
    }

    private class  BezierListener implements  AnimatorValue.ValueUpdateListener {

        private LeafHolder target;

        private Point point1;
        private  Point point2;

        private  Point point0;
        private  Point point3;

        int leafFlyStartY = (int) (mCurrentProgressBounds.bottom - mLeafDrawable.getHeight());
        int leafFlyRange  = (int) (mCurrentProgressBounds.getHeight() - mLeafDrawable.getHeight());

        int startPointY = leafFlyStartY - mRandom.nextInt(leafFlyRange);
        int endPointY   = leafFlyStartY - mRandom.nextInt(leafFlyRange);

        public BezierListener(LeafHolder target, RectFloat leafFlyRect) {
            this.target = target;
            point1 = getPoint1(leafFlyRect);
            point2 = getPoint2(leafFlyRect);
            point0 = new Point((int) (leafFlyRect.right - mLeafDrawable.getWidth()), startPointY);
            point3 =  new Point(leafFlyRect.left, endPointY);
        }

        @Override
        public void onUpdate(AnimatorValue animatorValue, float v) {
            float t   = v;
            float tLeft = 1.0f - t;

            float x = (float) (point0.getPointX() * Math.pow(tLeft, 3) + 3 * point1.getPointX() * t * Math.pow(tLeft, 2) + 3 * point2.getPointX() * Math.pow(t, 2) * tLeft + point3.getPointX() * Math.pow(t, 3));
            float y = (float) (point0.getPointY() * Math.pow(tLeft, 3) + 3 * point1.getPointY() * t * Math.pow(tLeft, 2) + 3 * point2.getPointY() * Math.pow(t, 2) * tLeft + point3.getPointY() * Math.pow(t, 3));


            // 需要对象
            target.mLeafRect.set((int) x, (int) y,  (int) (x + mLeafDrawable.getWidth()), (int) (y + mLeafDrawable.getHeight()));
            target.mLeafRotation = target.mMaxRotation * v;
            // 如何出现动画效果的？


            addDrawTask(task);
        }
    }

    //get the pointF which belong to the right half side
    private Point getPoint1(RectFloat leafFlyRect) {
        Point point = new Point();
        point.modify(Math.abs(leafFlyRect.right - mRandom.nextInt((int) (leafFlyRect.getWidth() / 2))),
                Math.abs((int) (leafFlyRect.bottom - mRandom.nextInt((int) leafFlyRect.getHeight()))));
        return point;
    }

    //get the pointF which belong to the left half side
    private Point getPoint2(RectFloat leafFlyRect) {
        Point point = new Point();
        point.modify(Math.abs(leafFlyRect.left + mRandom.nextInt((int) (leafFlyRect.getWidth() / 2))),
                Math.abs( (int) (leafFlyRect.bottom - mRandom.nextInt((int) leafFlyRect.getHeight()))));
        return point;
    }
}
